#include <windows.h>
#include "config.h"
#include <VFLBuffer.h>
#include <WMRTypes.h>
#include <FTL.h>
#include <VFL.h>
#include <FIL.h>
#include "ll_nand.h"

#define NAND_BLOCK_PAGE			128
#define NAND_PAGE_SECTOR		4
#define NAND_PAGE_SIZE			NAND_PAGE_SECTOR*512
#define NAND_BLOCK_SIZE			NAND_BLOCK_PAGE*NAND_PAGE_SIZE

int NAND_IsBadBlock(UINT32 nBlock);
int NAND_ReadPage(UINT32 nBlock, UINT32 nPage, UINT8 *buffer);
int NAND_WritePage(UINT32 nBlock, UINT32 nPage, UINT8 *buffer);
int NAND_EraseBlock(UINT32 nBlock); 
int NAND_MarkBadBlock(UINT32 nBlock); 

int NAND_IsBadBlock(UINT32 nBlock)
{
	LowFuncTbl *tmpTbl=FIL_GetFuncTbl();
	UINT8 SBuf[128];
	UINT32 nBank, nPpn, nSctBitmap=0xf, nPlaneBitmap;
	UINT32 nPage;
	int bRet = TRUE;

	if (GET_DevType() == WMR_MLC)
	{
		nPage = PAGES_PER_BLOCK-1;
	}
	else
	{
		nPage = 0;
	}
	
	if(SECTORS_PER_PAGE == 8)
	{
		nBank = nBlock / (2*BLOCKS_PER_BANK);
		nPpn = ((nBlock%(2*BLOCKS_PER_BANK))/2)*NAND_BLOCK_PAGE + nPage;	
		nPlaneBitmap = (nBlock % 2 == 0)? 0x1:0x2;
	}
	else
	{
		nBank = nBlock / BLOCKS_PER_BANK;
		nPpn = nBlock * NAND_BLOCK_PAGE + nPage;	
		nPlaneBitmap = 0x1;
	}

	tmpTbl->Read(nBank, nPpn, nSctBitmap, nPlaneBitmap, NULL, SBuf, 0, 1);	
	
	if(SBuf[0]!=0xff)
		bRet = FALSE32;
	else
		bRet = TRUE32;

	return bRet;
}

int NAND_ReadPage(UINT32 nBlock, UINT32 nPage, UINT8 *buffer)
{
	LowFuncTbl *tmpTbl=FIL_GetFuncTbl();
	UINT32 nBank, nPpn, nSctBitmap=0xf, nPlaneBitmap;
	int bRet = TRUE;

	if(SECTORS_PER_PAGE == 8)
	{
		nBank = nBlock / (2*BLOCKS_PER_BANK);
		nPpn = ((nBlock%(2*BLOCKS_PER_BANK))/2)*NAND_BLOCK_PAGE + nPage;	
		nPlaneBitmap = (nBlock % 2 == 0)? 0x1:0x2;
	}
	else
	{
		nBank = nBlock / BLOCKS_PER_BANK;
		nPpn = nBlock * NAND_BLOCK_PAGE + nPage;	
		nPlaneBitmap = 0x1;
	}

	tmpTbl->Read(nBank, nPpn, nSctBitmap, nPlaneBitmap, buffer, NULL, 0, 1);	

	return bRet;
}

int NAND_WritePage(UINT32 nBlock, UINT32 nPage, UINT8 *buffer) 
{
	LowFuncTbl *tmpTbl=FIL_GetFuncTbl();
	UINT32 nBank, nPpn, nSctBitmap=0xf, nPlaneBitmap;

	if(SECTORS_PER_PAGE == 8)
	{
		nBank = nBlock / (2*BLOCKS_PER_BANK);
		nPpn = ((nBlock%(2*BLOCKS_PER_BANK))/2)*NAND_BLOCK_PAGE + nPage;	
		nPlaneBitmap = (nBlock % 2 == 0)? 0x1:0x2;
	}
	else
	{
		nBank = nBlock / BLOCKS_PER_BANK;
		nPpn = nBlock * NAND_BLOCK_PAGE + nPage;	
		nPlaneBitmap = 0x1;
	}

	tmpTbl->Write(nBank, nPpn, nSctBitmap, nPlaneBitmap, buffer, NULL);

	tmpTbl->Sync(0, FALSE32);
	
	return 1;
}

int NAND_EraseBlock(UINT32 nBlock) 
{
	LowFuncTbl *tmpTbl=FIL_GetFuncTbl();
	UINT32 nBank, nPbn, nPlaneBitmap;

	if(SECTORS_PER_PAGE == 8)
	{
		nBank = nBlock / (2*BLOCKS_PER_BANK);
		nPbn = (nBlock%(2*BLOCKS_PER_BANK))/2;
		nPlaneBitmap = (nBlock % 2 == 0)? 0x1:0x2;
	}
	else
	{
		nBank = nBlock / BLOCKS_PER_BANK;
		nPbn = nBlock;	
		nPlaneBitmap = 0x1;
	}

	IS_CHECK_SPARE_ECC = FALSE32;
	tmpTbl->Erase(nBank, nPbn, nPlaneBitmap);
	IS_CHECK_SPARE_ECC = TRUE32;

	tmpTbl->Sync(0, FALSE32);
	
	return 1;
}

int NAND_MarkBadBlock(UINT32 nBlock) 
{
	LowFuncTbl *tmpTbl=FIL_GetFuncTbl();
	UINT8 SBuf[128];
	UINT32 nBank, nPpn, nSctBitmap=0xf, nPlaneBitmap;
	UINT32 nPage;

	if (GET_DevType() == WMR_MLC)
	{
		nPage = PAGES_PER_BLOCK-1;
	}
	else
	{
		nPage = 0;
	}

	if(SECTORS_PER_PAGE == 8)
	{
		nBank = nBlock / (2*BLOCKS_PER_BANK);
		nPpn = ((nBlock%(2*BLOCKS_PER_BANK))/2)*NAND_BLOCK_PAGE + nPage;	
		nPlaneBitmap = (nBlock % 2 == 0)? 0x1:0x2;
	}
	else
	{
		nBank = nBlock / BLOCKS_PER_BANK;
		nPpn = nBlock * NAND_BLOCK_PAGE + nPage;	
		nPlaneBitmap = 0x1;
	}

	memset(SBuf,0xFF,sizeof(SBuf));
	SBuf[0] = 0;

	IS_CHECK_SPARE_ECC = FALSE32;
	tmpTbl->Write(nBank, nPpn, nSctBitmap, nPlaneBitmap, NULL, SBuf);
	IS_CHECK_SPARE_ECC = TRUE32;

	tmpTbl->Sync(0, FALSE32);
	
	return 1;
}